#include "sprite.h"



int mW_sprite_blit (BITMAP * surface, mW_sprite * sprite)
{

	int pixel_x;
	int pixel_y;
	
	BITMAP * current_tile;
	
	int name_width;
	int name_height;
	
	int textbox_x;
	int textbox_y;
	BITMAP * wordwrapped_text;
	
	if (sprite == NULL)
		return 0;
	
	current_tile = mW_sprite_get_tile(sprite);
	if (current_tile == NULL)
		mW_error("Received a null sprite tile");
	
	pixel_x = mW_map_get_x_pixel(mW_current_map, sprite->x);
	pixel_y = mW_map_get_y_pixel(mW_current_map, sprite->y);
	
	pixel_x -= (current_tile->w - mW_TILE_SIZE) / 2;
	
	pixel_x += sprite->offset_x;
	pixel_y += sprite->offset_y;
	
	acquire_bitmap(surface);
	mW_blit(current_tile, surface, pixel_x, pixel_y);
	release_bitmap(surface);
	
	// blit name
	if (sprite->name != NULL)
	{
		name_width = text_length(font, sprite->name);
		name_height = text_height(font);
		
		acquire_bitmap(surface);
		textout_centre_ex(surface,
		                  font,
		                  sprite->name,
		                  pixel_x + (current_tile->w / 2),
		                  pixel_y - name_height - 2,
		                  makecol(0x0, 0x0, 0),
		                  -1);
		release_bitmap(surface);	
	}
	
	// blit text
	if (sprite->speech_text != NULL)
	{
		
		textbox_x = pixel_x + (current_tile->w / 2) - (mW_tile_speech_bubble->w / 2);
		textbox_y = pixel_y - mW_tile_speech_bubble->h - 2;
		
		wordwrapped_text = mW_wordwrap_text (sprite->speech_text,
		                                     mW_tile_speech_bubble->w - 8,
		                                     mW_tile_speech_bubble->h - 8,
		                                     makecol(0x0, 0x0, 0x0));
		
		if (wordwrapped_text != NULL)
		{
			acquire_bitmap(surface);
			mW_blit(mW_tile_speech_bubble, surface, textbox_x, textbox_y);
			mW_blit(wordwrapped_text, surface, textbox_x + 4, textbox_y + 4);
			release_bitmap(surface);
			free(wordwrapped_text);
		}
		else
		{
			free(sprite->speech_text);
			sprite->speech_text = NULL;
			sprite->speech_timer = 0;
		}
		
	}
	
	return 1;
	
}



int mW_sprite_blit_all (BITMAP * surface)
{
	
	mW_sprite * sprite;
	
	mW_list_reset_iterator(mW_sprites, 1);
	sprite = mW_list_iterate(mW_sprites, 1);
	while (sprite != NULL)
	{
		mW_sprite_blit(surface, sprite);
		sprite = mW_list_iterate(mW_sprites, 1);
	}
	
	return 1;

}



int mW_sprite_blit_id (BITMAP * surface, int sprite_id)
{
	
	mW_sprite * sprite;
	
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	if (sprite == NULL)
		return 0;
		
	return mW_sprite_blit(surface, sprite);
	
}



int mW_sprite_center_map (int sprite_id, mW_map * map)
{
	
	mW_sprite * sprite;
	
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	if (sprite == NULL)
		mW_error("Tried to center map on sprite that could not be found.");
	
	sprite->center_map = map;
	
	return 1;
	
}



// Inserts a new sprite into mW_sprites and returns the id of the sprite
int mW_sprite_create ()
{
	
	mW_sprite * sprite;
	
	sprite = (mW_sprite *) malloc(sizeof(mW_sprite));
	
	if (sprite == NULL)
		mW_error("Error allocating memory for sprite.\n");
		
	sprite->x = 0;
	sprite->y = 0;
	
	sprite->destination_x = 0;
	sprite->destination_y = 0;
	
	sprite->offset_x = 0;
	sprite->offset_y = 0;
	
	sprite->path = NULL;
	
	sprite->name = NULL;
	
	sprite->animate_delay = mW_SPRITE_ANIMATE_DELAY;
	
	sprite->direction = mW_SPRITE_DIR_FRONT;
	
	sprite->speech_text = NULL;
	sprite->speech_timer = 0;
	
	sprite->center_map = NULL;
	
	sprite->l_vm = mW_lua_create();
	mW_sprite_lua_register(sprite->l_vm);
	
	sprite->front = mW_list_create();
	sprite->back  = mW_list_create();
	sprite->left  = mW_list_create();
	sprite->right = mW_list_create();
	sprite->walk_front = mW_list_create();
	sprite->walk_back  = mW_list_create();
	sprite->walk_left  = mW_list_create();
	sprite->walk_right = mW_list_create();
	
	sprite->id = mW_list_insert(mW_sprites, sprite);
	return sprite->id;
	
}



int mW_sprite_destroy (int sprite_id)
{
	
	mW_sprite * sprite;
	
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	
	if (sprite == NULL)
		return 0;
	
	if (sprite->name != NULL)
		free(sprite->name);
		
	if (sprite->path != NULL)
		mW_list_destroy(sprite->path);
		
	if (sprite->speech_text != NULL)
		free(sprite->speech_text);
	
	mW_lua_destroy(sprite->l_vm);
		
	mW_list_destroy(sprite->front);
	mW_list_destroy(sprite->back);
	mW_list_destroy(sprite->left);
	mW_list_destroy(sprite->right);
	mW_list_destroy(sprite->walk_front);
	mW_list_destroy(sprite->walk_back);
	mW_list_destroy(sprite->walk_left);
	mW_list_destroy(sprite->walk_right);
	
	mW_list_delete(mW_sprites, sprite_id);
	
	return 1;
	
}



BITMAP * mW_sprite_get_tile (mW_sprite * sprite)
{
	
	BITMAP * current_tile;
	
	mW_list * tiles_list;
	
	if ((sprite->x == sprite->destination_x) && (sprite->y == sprite->destination_y)
	    && (sprite->offset_x == 0) && (sprite->offset_y == 0))
	{
		
		switch (sprite->direction)
		{
			case mW_SPRITE_DIR_FRONT :
				tiles_list = sprite->front;
				break;
			case mW_SPRITE_DIR_LEFT :
				tiles_list = sprite->left;
				break;
			case mW_SPRITE_DIR_BACK :
				tiles_list = sprite->back;
				break;
			case mW_SPRITE_DIR_RIGHT :
				tiles_list = sprite->right;
				break;
			default :
				tiles_list = sprite->front;
				break;
		}
		
	}
	else
	{
	
		switch (sprite->direction)
		{
			case mW_SPRITE_DIR_FRONT :
				tiles_list = sprite->walk_front;
				break;
			case mW_SPRITE_DIR_LEFT :
				tiles_list = sprite->walk_left;
				break;
			case mW_SPRITE_DIR_BACK :
				tiles_list = sprite->walk_back;
				break;
			case mW_SPRITE_DIR_RIGHT :
				tiles_list = sprite->walk_right;
				break;
			default :
				tiles_list = sprite->walk_front;
				break;
		}
	
	}
	
	if (sprite->animate_delay-- == 0)
	{
		sprite->animate_delay = mW_SPRITE_ANIMATE_DELAY;
		current_tile = mW_list_iterate(tiles_list, 1);
	}
	else
	{
		current_tile = mW_list_dont_iterate(tiles_list);
	}
	if (current_tile == NULL)
	{
		mW_list_reset_iterator(tiles_list, 1);
		current_tile = mW_list_iterate(tiles_list, 1);
	}
	
	return current_tile;
	
}



int mW_sprite_load_config (int sprite_id, char * config_filename)
{
	
	mW_sprite * sprite;
	
	// this is the top variable, the tiles table
	mW_lua_variable * tiles_variable;
	
	// this is a pointer to the variable beneath table,
	//   ie table.front
	mW_lua_variable * filenames;
	
	// this is a pointer to a filename in filenames
	mW_lua_variable * filename;
	
	// this is a pointer to the sprite tiles list we are working on,
	//   IE sprite->front
	mW_list * tiles_list;
	
	// load the tile bitmap into tile_bitmap before inserting it into
	//   tiles_list
	BITMAP * tile_bitmap;
	

	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	
	// this will execute the configuration file
	if (mW_lua_run_file(sprite->l_vm, config_filename) == 0)
		return 0;
	
	// this will grab the tiles table and place it in tiles
	lua_getglobal(sprite->l_vm, "tiles");
	tiles_variable = mW_lua_get_table(sprite->l_vm);
	lua_settop(sprite->l_vm, -1);
	if (tiles_variable == NULL)
		return 0;
	
	// the first variable should be of type list
	if (tiles_variable->data_type != mW_LUA_TYPE_TABLE)
		return 0;
	
	// iterate through each element in tiles table
	mW_list_reset_iterator(tiles_variable->data, 1);
	filenames = mW_list_iterate(tiles_variable->data, 1);
	while (filenames != NULL)
	{
		
		// the key_type should be string, data_type table
		if ((filenames->key_type != mW_LUA_TYPE_STRING)
		    || (filenames->data_type != mW_LUA_TYPE_TABLE))
		{
			mW_list_iterate(tiles_variable->data, 1);
			continue;
		}
		
		// find out which tile list we are working on and clear it
		if (strcmp(filenames->key, "front") == 0)
			tiles_list = sprite->front;
		else if (strcmp(filenames->key, "left") == 0)
			tiles_list = sprite->left;
		else if (strcmp(filenames->key, "right") == 0)
			tiles_list = sprite->right;
		else if (strcmp(filenames->key, "back") == 0)
			tiles_list = sprite->back;
		else if (strcmp(filenames->key, "walk_front") == 0)
			tiles_list = sprite->walk_front;
		else if (strcmp(filenames->key, "walk_left") == 0)
			tiles_list = sprite->walk_left;
		else if (strcmp(filenames->key, "walk_back") == 0)
			tiles_list = sprite->walk_back;
		else if (strcmp(filenames->key, "walk_right") == 0)
			tiles_list = sprite->walk_right;
		else
		{
			mW_list_iterate(tiles_variable->data, 1);
			continue;
		}
		
		mW_list_delete_all(tiles_list);
		
		// load all the bitmaps into tiles_list
		mW_list_reset_iterator(filenames->data, 1);
		filename = mW_list_iterate(filenames->data, 1);
		while (filename != NULL)
		{
			
			// ensure the data is a string
			if (filename->data_type != mW_LUA_TYPE_STRING)
			{
				filename = mW_list_iterate(filenames->data, 1);
				continue;
			}
			
			// load the bitmap
			#if DEBUG_SPRITE == 1
				printf("loading bitmap %s\n", (char *) filename->data);
			#endif
			tile_bitmap = load_bitmap(filename->data, NULL);
			if (tile_bitmap == NULL)
			{
				mW_error_nonfatal("Error loading bitmap for sprite");
				filename = mW_list_iterate(filenames->data, 1);
				continue;
			}
			
			// insert bitmap into tiles_list
			mW_list_insert(tiles_list, tile_bitmap);
			
			filename = mW_list_iterate(filenames->data, 1);
			
		}
		
		filenames = mW_list_iterate(tiles_variable->data, 1);
	
	}
	
	// destroy the tile_variable
	mW_lua_variable_destroy(tiles_variable);
	
	// now we're going to call onLoad() for this sprite
	lua_getglobal(sprite->l_vm, "onLoad");
	if (lua_type(sprite->l_vm, -1) == LUA_TFUNCTION)
	{
		lua_pushinteger(sprite->l_vm, (lua_Integer) sprite_id);
		lua_pushinteger(sprite->l_vm, (lua_Integer) sprite->x);
		lua_pushinteger(sprite->l_vm, (lua_Integer) sprite->y);
		mW_lua_p_call(sprite->l_vm, 3, 0);
	}
	else
		lua_pop(sprite->l_vm, 1);
	
	return 1;
	
}
	


int mW_sprite_init ()
{
	
	mW_sprites = mW_list_create();
	if (mW_sprites == NULL)
		return 0;
	
	return 1;
	
}



int mW_sprite_move_to (int sprite_id, unsigned short dest_x, unsigned short dest_y)
{
	
	mW_sprite * sprite;
	
	// get the sprite
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	if (sprite == NULL)
		return 0;
	
	
	// if the sprite already has a path, destroy it
	if (sprite->path != NULL)
		mW_list_destroy (sprite->path);
	
	
	// use pathfinding to get a path from our current location to the destination
	sprite->path = mW_pathfinding_find_path(mW_current_map, sprite->x, sprite->y, dest_x, dest_y);
	
	if (sprite->path == NULL)
	{
		printf("asdf\n");
		return 0;
	}

	sprite->destination_x = dest_x;
	sprite->destination_y = dest_y;
	
	return 1;
	
}



// moves sprite one more location towards destination
int mW_sprite_next_location (mW_sprite * sprite)
{
	
	mW_pathfinding_point * next_point;
	
	if (sprite->path != NULL)
	{
		if (mW_list_get_size(sprite->path) > 0)
		{

			next_point = mW_list_get_first(sprite->path);
			
			if (next_point->x < sprite->x)
				sprite->direction = mW_SPRITE_DIR_LEFT;
			else if (next_point->x > sprite->x)
				sprite->direction = mW_SPRITE_DIR_RIGHT;
			else if (next_point->y < sprite->y)
				sprite->direction = mW_SPRITE_DIR_BACK;
			else if (next_point->y > sprite->y)
				sprite->direction = mW_SPRITE_DIR_FRONT;
			
			sprite->offset_x = ((int) sprite->x - (int) next_point->x) * mW_TILE_SIZE;
			sprite->offset_y = ((int) sprite->y - (int) next_point->y) * mW_TILE_SIZE;
			
			sprite->x = next_point->x;
			sprite->y = next_point->y;

			mW_list_delete_first(sprite->path);
			
		}
		else
		{
			mW_list_destroy(sprite->path);
			sprite->path = NULL;
			// call arriveAt() for this sprite
			lua_getglobal(sprite->l_vm, "arriveAt");
			if (lua_type(sprite->l_vm, -1) == LUA_TFUNCTION)
			{
				lua_pushinteger(sprite->l_vm, (lua_Integer) sprite->id);
				lua_pushinteger(sprite->l_vm, (lua_Integer) sprite->x);
				lua_pushinteger(sprite->l_vm, (lua_Integer) sprite->y);
				mW_lua_p_call(sprite->l_vm, 3, 0);
			}
			else
				lua_pop(sprite->l_vm, 1);
		}
	}
	
	
	return 1;
	
}

	

// modified version of mW_map_update_offsets
int mW_sprite_update ()
{
	
	mW_sprite * sprite;
	
	mW_list_reset_iterator(mW_sprites, 1);
	sprite = mW_list_iterate(mW_sprites, 1);
	while (sprite != NULL)
	{
		
		// update offsets
		if (sprite->offset_x > 0)
		{
			if (sprite->offset_x < mW_SPRITE_SPEED)
				sprite->offset_x = 0;
			else
				sprite->offset_x -= mW_SPRITE_SPEED;
		}
		else if (sprite->offset_x < 0)
		{
			if (sprite->offset_x * -1 < mW_SPRITE_SPEED)
				sprite->offset_x = 0;
			else
				sprite->offset_x += mW_SPRITE_SPEED;
		}
		
		
		if (sprite->offset_y > 0)
		{
			if (sprite->offset_y < mW_SPRITE_SPEED)
				sprite->offset_y = 0;
			else
				sprite->offset_y -= mW_SPRITE_SPEED;
		}
		else if (sprite->offset_y < 0)
		{
			if (sprite->offset_y * -1 < mW_SPRITE_SPEED)
				sprite->offset_y = 0;
			else
				sprite->offset_y += mW_SPRITE_SPEED;
		}
		
		// move along path, if need be
		if ((sprite->offset_x == 0) && (sprite->offset_y == 0) && (sprite->path != NULL))
			mW_sprite_next_location(sprite);
		
		// decrement speech_timer, possibly free speech_text
		if (sprite->speech_text != NULL)
		{
			if (sprite->speech_timer <= 0)
			{
				free(sprite->speech_text);
				sprite->speech_text = NULL;
			}
			else
				sprite->speech_timer--;
		}
		
		// center map on sprite, if sprite->center_map isn't null
		if (sprite->center_map != NULL)
		{
			mW_map_center(mW_current_map, sprite->x, sprite->y);
		}
		
		sprite = mW_list_iterate(mW_sprites, 1);
		
	}
	
	return 1;
	
}









/******************************
 * HERE LIE THE LUA FUNCTIONS *
 ******************************/



int mW_sprite_lua_register(lua_State * l_vm)
{

	lua_pushcfunction(l_vm, mW_sprite_lua_move_to);
	lua_setglobal(l_vm, "moveTo");
	
	lua_pushcfunction(l_vm, mW_sprite_lua_set_name);
	lua_setglobal(l_vm, "setName");
	
	lua_pushcfunction(l_vm, mW_sprite_lua_say);
	lua_setglobal(l_vm, "say");
	
	lua_pushcfunction(l_vm, mW_sprite_lua_face_front);
	lua_setglobal(l_vm, "faceFront");
	
	lua_pushcfunction(l_vm, mW_sprite_lua_face_left);
	lua_setglobal(l_vm, "faceLeft");
	
	lua_pushcfunction(l_vm, mW_sprite_lua_face_right);
	lua_setglobal(l_vm, "faceRight");
	
	lua_pushcfunction(l_vm, mW_sprite_lua_face_back);
	lua_setglobal(l_vm, "faceBack");
	
	return 1;
	
}
	
	

int mW_sprite_lua_move_to (lua_State * l_vm)
{
	
	int sprite_id;
	int x;
	int y;
	
	if (lua_gettop(l_vm) != 3)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if ((lua_isnumber(l_vm, 1) != 1) || (lua_isnumber(l_vm, 2) != 1) || (lua_isnumber(l_vm, 3) != 1))
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite_id = mW_lua_integer_to_int(lua_tointeger(l_vm, 1));
	x = mW_lua_integer_to_int(lua_tointeger(l_vm, 2));
	y = mW_lua_integer_to_int(lua_tointeger(l_vm, 3));
	
	if ((x < 0) || (x >= mW_current_map->width))
		lua_pushboolean(l_vm, 0);
		
	else if ((y < 0) || (y >= mW_current_map->height))
		lua_pushboolean(l_vm, 0);
		
	else
	{
		if (mW_sprite_move_to (sprite_id, (unsigned short) x, (unsigned short) y) == 1)
			lua_pushboolean(l_vm, 1);
		else
			lua_pushboolean(l_vm, 0);
	}
	
	return 1;
	
}



int mW_sprite_lua_set_name (lua_State * l_vm)
{
	
	int sprite_id;
	mW_sprite * sprite;
	
	const char * lua_string;
	size_t length;
	
	
	if (lua_gettop(l_vm) != 2)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if ((lua_isnumber(l_vm, 1) != 1) || (lua_isstring(l_vm, 2) != 1))
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite_id = mW_lua_integer_to_int(lua_tointeger(l_vm, 1));
	lua_string = lua_tolstring(l_vm, 2, &length);
	
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	if (sprite == NULL)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if (length > 20)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if (sprite->name != NULL)
		free(sprite->name);
		
	sprite->name = (char *) malloc(strlen(lua_string) + 1);
	memset(sprite->name, 0, strlen(lua_string) + 1);
	strcpy(sprite->name, lua_string);
	
	lua_pushboolean(l_vm, 1);
	return 1;

}



int mW_sprite_lua_say (lua_State * l_vm)
{
	
	int sprite_id;
	mW_sprite * sprite;
	
	const char * lua_string;
	size_t length;
	
	
	if (lua_gettop(l_vm) != 2)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if ((lua_isnumber(l_vm, 1) != 1) || (lua_isstring(l_vm, 2) != 1))
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite_id = mW_lua_integer_to_int(lua_tointeger(l_vm, 1));
	lua_string = lua_tolstring(l_vm, 2, &length);
	
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	if (sprite == NULL)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if (length > 80)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if (sprite->speech_text != NULL)
		free(sprite->speech_text);
		
	sprite->speech_text = (char *) malloc(strlen(lua_string) + 1);
	memset(sprite->speech_text, 0, strlen(lua_string) + 1);
	strcpy(sprite->speech_text, lua_string);
	
	sprite->speech_timer = mW_SPRITE_SPEECH_TIME;
	
	lua_pushboolean(l_vm, 1);
	return 1;

}



int mW_sprite_lua_face_front (lua_State * l_vm)
{
	
	int sprite_id;
	mW_sprite * sprite;
	
	if (lua_gettop(l_vm) != 1)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if (lua_isnumber(l_vm, 1) != 1)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite_id = mW_lua_integer_to_int(lua_tointeger(l_vm, 1));
	
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	if (sprite == NULL)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite->direction = mW_SPRITE_DIR_FRONT;
	
	lua_pushboolean(l_vm, 1);
	return 1;
	
}



int mW_sprite_lua_face_left (lua_State * l_vm)
{
	
	int sprite_id;
	mW_sprite * sprite;
	
	if (lua_gettop(l_vm) != 1)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if (lua_isnumber(l_vm, 1) != 1)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite_id = mW_lua_integer_to_int(lua_tointeger(l_vm, 1));
	
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	if (sprite == NULL)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite->direction = mW_SPRITE_DIR_LEFT;
	
	lua_pushboolean(l_vm, 1);
	return 1;
	
}



int mW_sprite_lua_face_right (lua_State * l_vm)
{
	
	int sprite_id;
	mW_sprite * sprite;
	
	if (lua_gettop(l_vm) != 1)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if (lua_isnumber(l_vm, 1) != 1)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite_id = mW_lua_integer_to_int(lua_tointeger(l_vm, 1));
	
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	if (sprite == NULL)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite->direction = mW_SPRITE_DIR_RIGHT;
	
	lua_pushboolean(l_vm, 1);
	return 1;
	
}



int mW_sprite_lua_face_back (lua_State * l_vm)
{
	
	int sprite_id;
	mW_sprite * sprite;
	
	if (lua_gettop(l_vm) != 1)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	if (lua_isnumber(l_vm, 1) != 1)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite_id = mW_lua_integer_to_int(lua_tointeger(l_vm, 1));
	
	sprite = mW_list_get_by_id(mW_sprites, sprite_id);
	if (sprite == NULL)
	{
		lua_pushboolean(l_vm, 0);
		return 1;
	}
	
	sprite->direction = mW_SPRITE_DIR_BACK;
	
	lua_pushboolean(l_vm, 1);
	return 1;
	
}
